package practice.server;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * 基于线程池的简单 Web 服务器
 * 服务端并发获取静态资源
 *
 * @author insight
 * @since 2021/9/9
 */
public class SimpleServerByExecutor {
    private int threadCnt = 8;
    private ThreadPool<HttpRequestHandler> pool
            = new DefaultThreadPool<>(threadCnt);
    private static String basePath;
    private ServerSocket serverSocket;
    private static int port = 8080;

    public void setBasePath(String basePath) {
        if (basePath != null) {
            Path path = Paths.get(basePath);
            if (Files.exists(path) && Files.isDirectory(path)) {
                SimpleServerByExecutor.basePath = basePath;
            }
        }
    }
    
    public void start() throws IOException {
        serverSocket = new ServerSocket(port);
        Socket socket;
        
        while ((socket = serverSocket.accept()) != null) {
            pool.execute(new HttpRequestHandler(socket));
        }
        
        serverSocket.close();
    }

    static class HttpRequestHandler implements Runnable {
        private Socket socket;

        public HttpRequestHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            BufferedReader reader = null;
            PrintWriter out = null;
            try {
                out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(),
                        StandardCharsets.UTF_8));
                reader =
                        new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String header = reader.readLine();
                // header: get/post resources protocol
                String filePath = basePath + header.split(" ")[1];

                if (filePath.endsWith(".jpg")) {
                    // 没使用缓冲读取 满了几十倍
                    // InputStream in =
                    //         Files.newInputStream(Paths.get(filePath));
                    BufferedInputStream in =
                            new BufferedInputStream(new FileInputStream(filePath));
                    ByteArrayOutputStream bout =
                            new ByteArrayOutputStream();
                    int i;
                    while ((i = in.read()) != -1) {
                        bout.write(i);
                    }
                    byte[] bytes = bout.toByteArray();
                    // 这里需要遵循协议返回消息体 否则无法正常响应
                    out.println("HTTP/1.1 200 OK");
                    out.println("Server: Molly");
                    out.println("Content-Type: image/jpeg");
                    out.println("Content-Length: " + bytes.length);
                    out.println("");
                    out.flush();
                    socket.getOutputStream().write(bytes);
                }
            } catch (IOException e) {
                assert out != null;
                out.println("500");
                out.flush();
            } finally {
                close(reader, out);
            }
        }
        
        private static void close(Closeable... closeables) {
            if (closeables == null) return ;
            
            for (Closeable closeable : closeables) {
                try {
                    closeable.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}